package com.wiscamp.ninechapters.problems.infrastructure.repositories;

import com.wiscamp.ninechapters.problems.domain.models.tasks.Assignment;
import com.wiscamp.ninechapters.problems.domain.models.tasks.AssignmentDetail;
import com.wiscamp.ninechapters.problems.domain.repositories.AssignmentRepository;
import com.wiscamp.ninechapters.problems.infrastructure.converters.AssignmentConverter;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.tasks.AssignmentDetailMapper;
import com.wiscamp.ninechapters.problems.infrastructure.mappers.tasks.AssignmentMapper;
import com.wiscamp.ninechapters.problems.infrastructure.po.tasks.AssignmentDetailPO;
import com.wiscamp.ninechapters.problems.infrastructure.po.tasks.AssignmentPO;
import cube.ddd.aspect.HandleDataException;
import cube.ddd.domain.BaseRepository;
import cube.ddd.utils.PersistenceUtils;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.Collection;
import java.util.Objects;

@Repository
public class AssignmentRepositoryImpl extends BaseRepository implements AssignmentRepository {
    private final AssignmentMapper assignmentMapper;

    private final AssignmentDetailMapper assignmentDetailMapper;

    public AssignmentRepositoryImpl(AssignmentMapper assignmentMapper, AssignmentDetailMapper assignmentDetailMapper) {
        this.assignmentMapper = assignmentMapper;
        this.assignmentDetailMapper = assignmentDetailMapper;
    }

    //region assignment
    private AssignmentPO getAssignmentPO(@Min(0) long assignmentId) {
        return PersistenceUtils.findById(assignmentId, assignmentMapper::findById);
    }

    private void loadDetails(Assignment assignment) {
        if (Objects.nonNull(assignment)) {
            var details = PersistenceUtils.getEntitiesById(assignment.getAssignmentId(), assignmentDetailMapper::findListByAssignment,
                    AssignmentConverter.Instance::toAssignmentDetail);
            assignment.setDetails(details);
        }
    }

    /**
     * Gets a assignment - 练习任务指派记录
     *
     * @param assignmentId
     * @return
     */
    @HandleDataException
    public Assignment getAssignment(@Min(0) long assignmentId) {
        var assignment = PersistenceUtils.findEntityById(assignmentId, assignmentMapper::findById,
                AssignmentConverter.Instance::toAssignment);
        loadDetails(assignment);
        return assignment;
    }

    /**
     * Gets assignments by a set
     *
     * @param setId
     * @return
     */
    @HandleDataException
    public Collection<Assignment> getAssignmentsBySet(@Min(0) long setId) {
        var assignments = PersistenceUtils.getEntitiesById(setId, assignmentMapper::findListBySet,
                AssignmentConverter.Instance::toAssignment);
        for (var assignment : assignments) {
            loadDetails(assignment);
        }
        return assignments;
    }

    @HandleDataException
    public int getAssignmentQuantityByDate(LocalDate datetimeStart, LocalDate datetimeEnd) {
        return assignmentMapper.findAssignmentQuantityByDate(datetimeStart, datetimeEnd);
    }

    /**
     * Creates a assignment
     *
     * @param assignment
     * @return
     */
    @HandleDataException
    public Assignment saveAssignment(@NotNull Assignment assignment) {
        // save assignment, assign to students by default
        long newId = 0;
        if (assignment.getAssignmentId() <= 0) {
            var assignmentPO = AssignmentConverter.Instance.toAssignmentPO(assignment);
            var newAssigmentPO = assignmentMapper.saveAndFlush(assignmentPO);
            newId = newAssigmentPO.getAssignmentId();

            for (var detail : assignment.getDetails()) {
                detail.setAssignmentId(newId);
                saveAssignmentDetail(detail);
            }
        } else {
            var existedPO = getAssignmentPO(assignment.getAssignmentId());
            var assignmentPO = AssignmentConverter.Instance.toAssignmentPO(assignment, existedPO);
            var newAssigmentPO = assignmentMapper.saveAndFlush(assignmentPO);
            newId = newAssigmentPO.getAssignmentId();

            for (var detail : assignment.getDetails()) {
                detail.setAssignmentId(newId);
                saveAssignmentDetail(detail);
            }
        }

        // save details
        return getAssignment(newId);
    }

    @HandleDataException
    public boolean deleteAssignment(long assignmentId) {
        assignmentMapper.deleteById(assignmentId);
        return true;
    }
    //endregion


    private AssignmentDetailPO getAssignmentDetailPO(long detailId) {
        return PersistenceUtils.findById(detailId, assignmentDetailMapper::findById);
    }

    public AssignmentDetail getAssignmentDetail(long detailId) {
        return PersistenceUtils.findEntityById(detailId, assignmentDetailMapper::findById,
                AssignmentConverter.Instance::toAssignmentDetail);
    }

    @HandleDataException
    public AssignmentDetail saveAssignmentDetail(@NotNull AssignmentDetail detail) {
        // save assignment, assign to students by default
        long newId = 0;
        if (detail.getDetailId() <= 0) {
            var detailPO = AssignmentConverter.Instance.toAssignmentDetailPO(detail);
            var newDetailPO = assignmentDetailMapper.saveAndFlush(detailPO);
            newId = newDetailPO.getDetailId();
        } else {
            var existedPO = getAssignmentDetailPO(detail.getDetailId());
            var detailPO = AssignmentConverter.Instance.toAssignmentDetailPO(detail, existedPO);
            var newDetailPO = assignmentDetailMapper.saveAndFlush(detailPO);
            newId = newDetailPO.getDetailId();
        }

        // save details
        return getAssignmentDetail(newId);
    }
}
